/**
 * @file : TimeIntegratorFactory.h
 * @author: fenghuwuyu
 * @version 1.0
 * @mail: 3148107006@qq.com
 * @date: 2021年04月19日 星期一 16时07分38秒
 * @brief:
 */

#ifndef TIMEINTEGRATORFACTORY_H
#define TIMEINTEGRATORFACTORY_H

#include <iostream>
#include <map>
#include "TimeIntegrator.h"
#include "RHS.h"

class TimeIntegratorFactory
{
	// Set the creator "TimeIntegratorCreator" which points to a timeintegrator.
	public:
		typedef TimeIntegrator* (*TimeIntegratorCreator)();

	// Set the hashtable which contains the methodname and related timeintegrator.
	private:
		typedef std::map<std::string, TimeIntegratorCreator> CallbackMap;
		CallbackMap TimeIntegratorMap;
	
	// Four interfaces:
	// The first is a registrational interface
	// The second is a unregistrational interface
	// The third is a pointer interface that can call the related timeintegrator 
	// The fourth is a interface that print the solve.
	public:
		bool RegisterTimeIntegrator(const std::string &TimeIntegratorID, TimeIntegratorCreator createFn);
		bool UnregisterTimeIntegrator(const std::string &TimeIntegratorID);
		TimeIntegrator* CreateTimeIntegrator(const std::string &TimeIntegratorID) const;

	// Singleton declare.
	private:
		TimeIntegratorFactory(){};

	// Singleton declare.
	public:
		TimeIntegratorFactory(const TimeIntegratorFactory&) = delete;
		TimeIntegratorFactory &operator=(const TimeIntegratorFactory&) = delete;
		static TimeIntegratorFactory& GetInstance(){static TimeIntegratorFactory Instance; return Instance;};
		~TimeIntegratorFactory(){TimeIntegratorMap.clear();};
};



namespace
{
	template <int order>
	TimeIntegrator* CreateAB()
	{
		return new AB<order>;
	};

	template <int order>
	TimeIntegrator* CreateAM()
	{
		return new AM<order>;
	};

	template <int order>
	TimeIntegrator* CreateBDF()
	{
		return new BDF<order>;
	};

	TimeIntegrator* CreateRK()
	{
		return new RK;
	};


	typedef TimeIntegrator* (*TimeIntegratorCreator)();
	TimeIntegratorCreator crt_RK = CreateRK;
	TimeIntegratorCreator crt_AB1 = CreateAB<1>;
	TimeIntegratorCreator crt_AB2 = CreateAB<2>;
	TimeIntegratorCreator crt_AB3 = CreateAB<3>;
	TimeIntegratorCreator crt_AB4 = CreateAB<4>;


	// then create a instance of TimeIntegratorFactory and register all the method and move this namespace into the main.cpp 
}
bool TimeIntegratorFactory::RegisterTimeIntegrator(const std::string &TimeIntegratorID, TimeIntegratorCreator createFn)
{
	return TimeIntegratorMap.insert(CallbackMap::value_type(TimeIntegratorID, createFn)).second;
}

bool TimeIntegratorFactory::UnregisterTimeIntegrator(const std::string &TimeIntegratorID)
{
	return TimeIntegratorMap.erase(TimeIntegratorID) == 1;
}


#else
// DO NOTHING
#endif

